﻿using AudoCutApp.Properties;
using Microsoft.Research.DynamicDataDisplay.Maps.DeepZoom;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Linq;
using PropertyChanged;
using Microsoft.Win32;
using NAudio.MediaFoundation;
using MessageBox = System.Windows.MessageBox;
using Path = System.IO.Path;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar;

namespace AudoCutApp
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    [AddINotifyPropertyChangedInterface]
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
            this.Closed += MainWindow_Closed;
            this.DataContext = this;
        }

        private void MainWindow_Closed(object sender, EventArgs e)
        {
            _audioFileReader?.Close();
            App.Current.Shutdown();
        }

        Pen pen = new Pen();

        public int Number { get; set; }

        public int NumberLength { get; set; }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            pen = new Pen();
            pen.Thickness = 1;
            pen.LineJoin = PenLineJoin.Round;
            pen.EndLineCap = PenLineCap.Round;
            pen.Brush = new SolidColorBrush(Color.FromRgb(0, 0, 0));
            Number = Settings.Default.currentNumber;

            NumberLength = Settings.Default.numberLength;

            OutputFolder = outbasePath = Settings.Default.BaseOutPath;

            RangLength = Settings.Default.RangleLength;

        }

        AudioFileReader _audioFileReader;
        List<Point> lineData = new List<Point>();
        int zoom = 1;
        int allWidth = 0;
        public string CurrentPath { get; set; }
        public string OutputFolder { get; set; }
        private string outbasePath = "D:\\";
        public int RangLength { get; set; } = 50;
        float[] wavdata;
        /// <summary>
        /// 开始画波形
        /// </summary>
        /// <param name="fileName"></param>
        public void BeginDrawWaveLine()
        {
            if (wavdata==null||wavdata.Length==0)
            {
                return;
            }
            lineData.Clear();
            flateCanvas.Children.Clear();
            mainCanvas.Children.Clear();
            var ww = mainCanvas.ActualWidth;
            allWidth = (int)ww;
            var yScale = mainCanvas.ActualHeight / 2;
            var max = wavdata.Max();
            var min = wavdata.Min();
            var rang = mainCanvas.ActualHeight / (max - min) * 1.5;
            double x, y1, y2;
            zoom = wavdata.Length / (int)ww;

            for (int i = 0; i < ww; i++)
            {
                x = i;
                y1 = (int)(yScale - wavdata[i * zoom] * rang);
                y2 = (int)(yScale + wavdata[i * zoom] * rang);
                lineData.Add(new Point(x, y1));
                lineData.Add(new Point(x, y2));
            }



            if (lineData.Count > 1)
            {
                System.Windows.Shapes.Path fornthBack = new System.Windows.Shapes.Path()
                {
                    StrokeDashCap = PenLineCap.Flat,
                    StrokeLineJoin = PenLineJoin.Round,
                    Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0)),
                    StrokeThickness = 1,
                    StrokeDashOffset = 0,
                };

                SetPathData(fornthBack, lineData);
                mainCanvas.Children.Add(fornthBack);
            }

            DrawFlage();

            this.InvalidateVisual();
        }

        private bool OpenFile(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
                return false;
            lineData.Clear();
            _audioFileReader = new AudioFileReader(fileName);
            byte[] datas = new byte[_audioFileReader.Length];
            _audioFileReader.Read(datas, 0, datas.Length);
            wavdata = new float[datas.Length / sizeof(float)];

            Buffer.BlockCopy(datas, 0, wavdata, 0, datas.Length); return true;
        }

        private void DrawFlage()
        {
            List<ZeroInfo> zeroInfos = new List<ZeroInfo>();
            int startIndex = -1, endindex = -1;
            List<Point> tempData = new List<Point>();
            List<Point> aftertempData = new List<Point>();
            int index = 0;

            for (int i = 0; i < lineData.Count; i++)
            {

                if (startIndex < 0)
                {
                    if (Math.Abs(lineData[i].Y - 50) > 5)
                    {
                        int startmin = i > 15 ? 15 : 0;
                        startIndex = i - startmin;
                    }
                    else continue;
                }
                else if (endindex < 0)
                {
                    int count = i + RangLength < lineData.Count ? RangLength : lineData.Count - i - 1;
                    var checkDatas = lineData.GetRange(i, count);
                    if (checkDatas.All(p => Math.Abs(p.Y - 50) < 5))
                    {
                        endindex = i + 15;
                        i = endindex;
                        ZeroInfo zero = new ZeroInfo() { Start = (int)lineData[startIndex].X, End = (int)lineData[endindex].X };
                        zeroInfos.Add(zero);
                        startIndex = endindex = -1;
                    }
                }
            }


            var zeros = zeroInfos.OrderBy(p => p.Start).ToList();
  
            for (int i = 0; i < zeros.Count; i++)
            {
                var zero = zeros[i];
                var xx1 = zero.Start;
                var xx2 = zero.End;

                Line line1 = new Line() { X1 = xx1, Y1 = 95, X2 = xx1, Y2 = 100, StrokeThickness = 2, Stroke = new SolidColorBrush(Colors.Black) };
                Line line2 = new Line() { X1 = xx2, Y1 = 95, X2 = xx2, Y2 = 100, StrokeThickness = 2, Stroke = new SolidColorBrush(Colors.Black) };
                var mid=(xx1 + xx2)/2;
                TextBlock text1 = new TextBlock() { Text = xx1.ToString(), FontSize = 8 };
                Canvas.SetLeft(text1, xx1);
                Canvas.SetTop(text1, 90);
                TextBlock text2 = new TextBlock() { Text = xx2.ToString(), FontSize = 8 };
                TextBlock text3 = new TextBlock() { Text = (i+1).ToString(), FontSize = 10 ,Foreground=new SolidColorBrush(Colors.Red) };
                Canvas.SetLeft(text2, xx2);
                Canvas.SetTop(text2, 90);
                Canvas.SetTop(text3, 70);
                Canvas.SetLeft(text3, mid);
                flateCanvas.Children.Add(line1);
                flateCanvas.Children.Add(line2);
                flateCanvas.Children.Add(text1);
                flateCanvas.Children.Add(text2);
                flateCanvas.Children.Add(text3);


                RactangControl rectangle = new RactangControl();
                mainCanvas.Children.Add(rectangle);
                rectangle.StartPoint = new Point(xx1, 0);
                rectangle.EndPoint = new Point(xx2, 0);
                rectangle.Height = mainCanvas.ActualHeight;
                Canvas.SetLeft(rectangle, xx1);
            }
        }

        private void OnLoadFile(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.FileName = Settings.Default.LastFilePath;
            openFile.Multiselect = false;
            if (openFile.ShowDialog() == true)
            {
                CurrentPath = openFile.FileName;
                OutputFolder = $"{outbasePath}\\{Path.GetFileNameWithoutExtension(CurrentPath)}";
                if (!OpenFile(CurrentPath)) return;
                BeginDrawWaveLine();
                Settings.Default.LastFilePath = Path.GetDirectoryName(CurrentPath);
                Settings.Default.Save();
            }

        }


        private static void SetPathData(System.Windows.Shapes.Path pathBack, List<Point> points)
        {
            if (points.Count <= 1) return;
            PathFigure pathFigure = new PathFigure() { StartPoint = points[0] };
            PolyLineSegment polyLine = new PolyLineSegment() { Points = new PointCollection(points.Skip(1).ToArray()) };
            pathFigure.Segments.Add(polyLine);
            pathBack.Data = new PathGeometry(new PathFigure[] { pathFigure });

        }

        private void mainCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            BeginDrawWaveLine();

        }

        bool isStartDrow = false;
        Point startPoint;
        Point endPoint;
        private void MouseLeftButtonDown_Click(object sender, MouseButtonEventArgs e)
        {
            startPoint = e.GetPosition(mainCanvas);
            tempCanvas.Children.Clear();
            bool isContains = false;
            foreach (var item in mainCanvas.Children)
            {
                if (item is RactangControl rac)
                {
                    if (startPoint.X > rac.StartPoint.X && startPoint.X < rac.EndPoint.X)
                    {
                        isContains = true;
                    }
                }
            }

            if (!isContains)
            {
                isStartDrow = true;
                AddRectang(startPoint, startPoint);
            }

        }


        private void AddRectang(Point start, Point end)
        {
            tempCanvas.Children.Clear();
            RactangControl rectangle = new RactangControl();
            rectangle.StartPoint = start.X < end.X ? start : end;
            rectangle.EndPoint = start.X < end.X ? end : start;
            var width = Math.Abs(end.X - start.X);
            if (start == end || width < 4)
            {
                rectangle.Width = 2;
            }
            else
            {
                rectangle.Width = width - 4;
            }
            rectangle.Height = tempCanvas.ActualHeight;
            Canvas.SetLeft(rectangle, start.X < end.X ? start.X + 2 : end.X + 2);
            tempCanvas.Children.Add(rectangle);
        }



        /// <summary>
        /// 查找父控件
        /// </summary>
        /// <typeparam name="T">父控件的类型</typeparam>
        /// <param name="obj">要找的是obj的父控件</param>
        /// <param name="name">想找的父控件的Name属性</param>
        /// <returns>目标父控件</returns>
        public static T GetParentObject<T>(DependencyObject obj, string name) where T : FrameworkElement
        {
            DependencyObject parent = VisualTreeHelper.GetParent(obj);

            while (parent != null)
            {
                if (parent is T && (((T)parent).Name == name | string.IsNullOrEmpty(name)))
                {
                    return (T)parent;
                }

                // 在上一级父控件中没有找到指定名字的控件，就再往上一级找
                parent = VisualTreeHelper.GetParent(parent);
            }

            return null;
        }

        private void MouseLeftButtonUp_Click(object sender, MouseButtonEventArgs e)
        {
            if (isStartDrow)
            {
                isStartDrow = false;
                var rectangle = (RactangControl)tempCanvas.Children[0];
                tempCanvas.Children.Clear();
                mainCanvas.Children.Add(rectangle);
            }
        }

        private void MouseMove_Click(object sender, MouseEventArgs e)
        {
            endPoint = e.GetPosition(mainCanvas);
            if (isStartDrow)
            {

                AddRectang(startPoint, endPoint);
            }

            foreach (var rectangle in mainCanvas.Children)
            {
                if (rectangle is RactangControl rac)
                {
                    rac.MouseDownMove(e);
                }
            }

        }



        private void Save(object sender, RoutedEventArgs e)
        {
            Directory.CreateDirectory(OutputFolder);
            List<RactangControl> ractangs = new List<RactangControl>();
            foreach (var item in mainCanvas.Children)
            {
                if (item is RactangControl rac)
                {
                    ractangs.Add(rac);
                }
            }
            var recs = ractangs.OrderBy(p => p.StartPoint.X).ToList();

            for (int i = 0; i < recs.Count; i++)
            {
                var name = i == 0 ? "title" : Number.ToString().PadLeft(NumberLength, '0');
                var path = $"{OutputFolder}\\{name}.wav";
                using (var source = new AudioFileReader(CurrentPath))
                {
                    var item = recs[i];

                    double zoom = source.TotalTime.TotalMilliseconds * 1.0f / allWidth;
                    int skip = (int)(zoom * item.StartPoint.X);
                    int tak = (int)(zoom * item.EndPoint.X);
                    var audio = new OffsetSampleProvider(source)
                    {
                        SkipOver = TimeSpan.FromMilliseconds(skip),
                        Take = TimeSpan.FromMilliseconds(tak - skip),

                    };
                    WaveFileWriter.CreateWaveFile16(path, audio);
                }
                var inputFileName = path;
                var outputFileName = inputFileName.Substring(0, inputFileName.Length - 3) + "mp3";

                var mediaType = MediaFoundationEncoder.SelectMediaType(
                                    AudioSubtypes.MFAudioFormat_MP3,
                                    new WaveFormat(44100, 1),
                                    0);
                using (var reader = new MediaFoundationReader(inputFileName))
                {
                    using (var encoder = new MediaFoundationEncoder(mediaType))
                    {
                        encoder.Encode(outputFileName, reader);
                    }
                }
                File.Delete(path);
                if (i > 0)
                    Number++;
            }

            Settings.Default.RangleLength = RangLength;
            Settings.Default.numberLength = NumberLength;
            Settings.Default.currentNumber = Number;
            Settings.Default.Save();
            MessageBox.Show("导出完成");
        }

        private void SelectOutPath(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
            dialog.SelectedPath = outbasePath;
            dialog.Description = "请选择输出文件夹";
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (!string.IsNullOrEmpty(dialog.SelectedPath))
                {
                    outbasePath = dialog.SelectedPath;
                    OutputFolder = $"{outbasePath}\\{Path.GetFileNameWithoutExtension(CurrentPath)}";
                    Settings.Default.BaseOutPath = outbasePath;
                    Settings.Default.Save();
                    // OutputFolder = OutputFolder dialog.SelectedPath;
                }
            }
        }

        private void Clear(object sender, RoutedEventArgs e)
        {
            mainCanvas.Children.Clear();
        }

        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            BeginDrawWaveLine();
        }
    }

    public class ZeroInfo
    {
        public int Start { get; set; }
        public int End { get; set; }
        public int Length { get { return End - Start; } }
        public List<int> Data { get; set; } = new List<int>();

    }
}
